#include "AQbuffer.h"

#include <cstring>
#include <iostream>
#include<sys/uio.h>
using namespace AQBUFFER;

BUFFER::BUFFER() : readIndex(BUFFER::prependsize),
                   writeIndex(BUFFER::prependsize),
                   buffer(BUFFER::initsize)
{
    ;
}

char *BUFFER::Begin()
{
    return &*buffer.begin();
}

int BUFFER::size()
{
    return buffer.size(); 
}

void BUFFER::hTon(void *data, int len)
{
    for (int i = 0; i < len / 2; i++)
    {
        std::swap(*((char *)data+i),*((char *)data+len-i-1));
    }
}

void BUFFER::nToh(void *data, int len)
{
    hTon(data, len);
}

unsigned int BUFFER::prependable()
{
    return readIndex;
}

unsigned int BUFFER::readable()
{
    return writeIndex - readIndex;
}

unsigned int BUFFER::writable()
{
    return buffer.size() - writeIndex;
}

char *BUFFER::beginRead()
{
    return Begin() + readIndex;
}

char *BUFFER::beginWrite()
{
    return Begin() + writeIndex;
}

void BUFFER::fix_readIndex(int len)
{
    readIndex += len;
}

void BUFFER::fix_writeIndex(int len)
{
    writeIndex += len;
}

void BUFFER::makeSpace(int len) //fixed move readable data!
{
    if (readIndex + writable() < len + prependsize)
    {
        buffer.resize(writeIndex + len);
    }
    unsigned tmp = readable();
    std::copy(beginRead(), beginWrite(), Begin() + prependsize);
    readIndex = prependsize;
    writeIndex = prependsize + tmp;
}

void BUFFER::write(const char *data, int len)
{
    if (writable() < len)
    {
        makeSpace(len);
    }
    std::copy(data, data + len, beginWrite());
    writeIndex+=len;
}
void BUFFER::write(const void *data,int len)
{
    write(static_cast<const char*>(data),len);
}

void BUFFER::prepend(int len)
{
    
    readIndex-=sizeof(int);
    hTon(&len,sizeof(int));
    static void *data=&len;
    const char*p=static_cast<const char*>(data);
    std::copy(p,p+sizeof(int),beginRead());  
}

void BUFFER::writeint(int x)
{
    int len = sizeof(int);
    hTon(&x, len);
    write(&x, len);
}

void BUFFER::writestring(std::string &s)
{
    int len=s.size();
    const char*c=s.data();
    write(c,len);
    prepend(len);
}

int BUFFER::readint()
{
    int ans=0;
    int len=sizeof(int);
    std::memcpy(&ans,beginRead(),len);
    nToh(&ans,len);
    readIndex+=len;
    return ans;
}

std::string BUFFER::readstring(int len)
{
    if(len>readable())
    {
        return "";
    }
    std::string ans(beginRead(),len);
    readIndex+=len;
    return ans;
}

ssize_t BUFFER::readFd(int fd)
{
    char extrabuf[2048];
    struct iovec vec[2];
    vec[0].iov_base=beginWrite();
    vec[0].iov_len=writable();
    vec[1].iov_base=extrabuf;
    vec[1].iov_len=sizeof(extrabuf);
    
    int iovcnt=2;
    const ssize_t n=readv(fd,vec,iovcnt);
    if(n<0)
    {
        return -1;
    }
    else if(static_cast<int>(n)<=writable())
    {
        writeIndex+=static_cast<int>(n);
    }
    else
    {
        int wtb=writable();
        writeIndex=buffer.size();
        write(extrabuf,n-wtb);
    }
    return n;
}
